FEZ
Volume Number: 10
Issue Number: 9
Column Tag: 8th Annual MacHax™ Best Hack Contest
Pushing the Envelope with FEZ
Frame Evading ZoomRects take the top prize at MacHack
By Doug McKenna, Chief Hierarchæologist, Mathemæsthetics, Inc.
Note: Source code files accompanying article are located on MacTech CD-ROM or
source code disks.
About the Author
Doug McKenna is president of Mathemæsthetics, Inc. and author of Resorcerer®,
the premiere and Eddy-award-winning Macintosh resource editor. Among his
childhood hacks were a variety of ingeniously designed and less-than-benign
mousetraps, as well as a private hand-built telephone line to a friend’s house. The line
was eventually destroyed by lightning (fortunately the houses grounding either end
weren’t). His first computer amusement was a canonical ASR-33 teletype paper-tape
jingle bell hack. Although (or perhaps because) his parents let him play with matches
at age six, fireworks at nine, and dynamite at twelve, his pyromaniacal tendencies have
long since evolved into more constructive endeavors in the explosive virtual world of
editing interfaces.
The Lessons Of Two Old Hacks
Back in the early 70’s, when I was more of an innocent lad than I am now, I had a
summer job in the MIS department of a large industrial tool company where I got to
hack out BASIC programs on a teletype-based system. One day, I came across a
program called Screwball (author unknown), which provided me with the first and
probably the most important lesson I’ve ever learned about user-interfaces.
Screwball was a typical practical joke hack. Some would say it had no
social-redeeming value, or that it was a proto-virus. But I can still feel the utter
amazement I had when I finally realized what it did. Or rather, what it’s author had
done to my head. Upon running Screwball, I (the user) was presented with some silly
question, the actual wording of which I no longer remember. Regardless of the answer
typed back, the teletype responded with some equally silly or insulting
(“screwbally”) answer, and then the program ostensibly exited back to BASIC’s
command line shell. Except that it didn’t: if I recall correctly, Screwball used the
then-relatively-new CHAIN command to secretly (or rather, silently) transfer
control to another program whose entire user-interface was the same as BASIC’s
interpreter, only things didn’t work quite right! The programs in the workspace
directory wouldn’t run; strange error messages would arise under what used to be
normal conditions; etc. When you tried to LIST SCREWBALL.BAS (or whatever),
Screwball would list itself with a modification that excluded the final CHAIN
instruction, so regaining your bearings in the face of this rogue program’s control
over your perceptions was not a trivial task.
I’ve forgotten whether I figured out how Screwball worked, or whether
Screwball itself was eventually forgiving enough to let me understand (that is, to truly
exit after some not-too-secret incantation), but when I did figure it out I had a real
epiphany: a computer program could be about more than just computing, it could be
about controlling another person’s perceptions, which, for ill or for good, is the heart
of what a user-interface is all about.
As an April Fool’s joke a few years later, I created my own version of Screwball,
only this time it was for the entire DEC PDP-10 operating system’s
command-line-interface and commonly-run system utilities, which included a variety
of user-interfaces, including a full-screen source code text editor, all of which had to
be cobbled together enough to fool and annoy an accomplished user for, say, a minimum
of 5-10 minutes. Having nothing better to do, it took me two weeks of hacking
18/hours a day to create it in Fortran and assembly. What I learned from the hack was
that it is always a lot easier creating an inconsistent interface than it is designing a
consistent one. And also that the sleep re searchers were right about the natural human
sleep/wake cycles being longer than 24 hours in the absence of natural cues, of which
most computer rooms of the time were devoid.
The lesson of both these hacks is that a user-interface can immerse the user in a
metaphor at a different level than the underlying computation, and if the metaphor is
appropriate and self-consistent then all is well and productive for the user. If not, the
user will inevitably become frustrated, or will waste time thinking about the
computer rather than the task at hand (or maybe will be the butt of a practical joke!).
Screwball and its ilk were intentionally designed to be frustrating; our modern
graphical user-interfaces are, with only partial success, designed not to be.
Which brings me to why I wrote my FEZ hack for the MacHack/MacHax
conference/contest. It’s my little contribution to a more consistent graphical user
interface on the Mac, and it partially solves a visual problem that has bo thered me for
a couple of years now. With machines being so much more powerful these days than
ten years ago, doing the extra computation isn’t a problem. And it really looks way
cool!
Standard ZoomRects
In the Mac Finder and other graphical desktop user-interfaces, icons represent
documents, applications, folders, or other types of system objects. Internally, these
are usually files that can be opened or closed, although the act of opening or closing the
various classes of icons can mean different things. Usually, opening an icon means that
another window gets created on the desktop. It is the Finder’s main purpose in life to
support the graphical metaphor that the underlying hierarchical file system is a
series of nested folders whose windows show the contents of the folders they represent.
When you double-click on a folder icon in a Finder window, the new window
appears at its last position. From a visual logic point of view, this is fairly
unambiguous, because you know which icon you just clicked on (and you don’t really
care about it once the window is opened), and you know where the window that just
opened is. However, in the opposite situation when you close a folder window on the
desktop, it is not always easy to see which folder icon among the many icons in the
underlying window is the representative icon for the window being closed. Thus was
born the idea of zooming rectangles, which is a simple technique to provide animated
visual feedback showing the link between a window and its icon elsewhere on the
desktop.
The current zooming rectangles algorithm, usually known among Mac
programmers as the ZoomRect routine (you have to roll your own; it’s not in the
toolbox), takes as input the bounds of an icon, the bounds of a window frame, and the
direction of the zoom. Because the animation in general takes place between windows
on the desktop, all coordinates must be in global desktop coordinates and all drawing
has to be in the global Window Manager port. This in turn means that all drawing must
be non-destructive: if you muck with a pixel on the desktop, it is your responsibility
to restore it to its old value as soon as possible, because pixels on the desktop (that is,
in the Window Manager port) are shared among applications (processes). In the
current cooperative multitasking environment, you can take control of the desktop
pixels as long as you restore them prior to allowing the system control again. Drawing
something twice in exclusive-OR mode is the easiest and fastest method of doing this.
[NOTE: In the future, with pre-emptive multitasking, drawing to the desktop will of
necessity be even more constrained since any one process may not have any knowledge
of when other processes are also writing to the desktop.]
Figure 1: Standard zoom from a visible icon
The standard ZoomRect routine creates a series of rectangles, with each one being
part of a simple linear interpolation in global screen coordinates between the two
boundary rectangles. Most ZoomRect implementations interpolate between
corresponding corners of the starting and ending rectangles; however, for my hack, I
began by re-implementing the standard routine to perform the entirely equivalent
interpolation between the centers of the two boundary rectangles, and to linearly
interpolate between the two sizes. I also chose to avoid the Fixed point routines so I
could keep my code simple:
ZoomCenterRect
This new routine does the same thing as a linear ZoomRect(), except that instead
of interpolating between the four corners of the two limiting Rects, we interpolate
along a line between the two limiting Rects’ centers, and between their two sizes. This
sets us up to provide a more general routine that follows any path, instead of the
implicit straight line that ZoomRect() would travel. This code doesn't care about the
direction of the zoom, which is now implicit in the order of the two rectangular
arguments; nor whether either of the Rect’s is empty. Both input Rect pointers must
be non-NIL and in global coordinates. The thickness parameter should normally be 1
pixel, but was added during MacHack to enhance the demo by giving more visual weight
to the zooming rectangles.
/* 1 */
void ZoomCenterRect(Rect *startRect, Rect *endRect, short thickness)
{
Point startCenter,endCenter,startSize,endSize;
Rect r1,r2,r3,r4; short zoomSteps,x,y,w,h; long i;
if (!InstallDesktop()) // Draw outside of all windows
return; // or do nothing at all if problem
// Get centers of the two limiting rectangles

startCenter.h = (startRect->left + startRect->right) / 2;
startCenter.v = (startRect->top + startRect->bottom) / 2;
endCenter.h = (endRect->left + endRect->right) / 2;
endCenter.v = (endRect->top + endRect->bottom) / 2;
// And the starting and ending half sizes
startSize.h = (startRect->right - startRect->left) / 2;
startSize.v = (startRect->bottom - startRect->top) / 2;
endSize.h = (endRect->right - endRect->left) / 2;
endSize.v = (endRect->bottom - endRect->top) / 2;